package Service::SystemCenterService;

use strict;
use warnings;
use 5.010;

use Digest::SHA qw(sha256_hex);

use Exporter qw(import);
use Native::DataCollector;
use Persistance::SystemCenterDao;
use Cache::CacheFactory;
use Utils::WebUtils;

# Private helper methods
my $get_cache_client = sub {
    my $cache_client = Cache::CacheFactory->get_client('Redis')->fetch_connection(reconnect => 60);

    return $cache_client;
};
# End of helper methods

sub get_current_pi_environment {
	my $cpu_temperature = Native::DataCollector::collect_current_pi_cpu_temperature();
	my $gpu_temperature = Native::DataCollector::collect_current_pi_gpu_temperature();
	my $cpu_usage = Native::DataCollector::collect_current_cpu_usage();
	my $memory_usage = Native::DataCollector::collect_current_memory_usage();
	my $system_load = Native::DataCollector::collect_current_system_load();
	my $system_uptime = Native::DataCollector::collect_current_system_uptime();

	my %current_data = (
		cpu_temperature => $cpu_temperature,
		gpu_temperature => $gpu_temperature, 
		cpu_usage => $cpu_usage,
		memory_usage => $memory_usage,
		system_load => $system_load,
		system_uptime => $system_uptime,
	);
	my @data = (\%current_data);

	return @data;
}

sub get_all_users_list {
	my @data = Persistance::SystemCenterDao::get_all_users();

	return @data;
}

sub get_user_by_id {
    my $user_id = shift;
    my @data = Persistance::SystemCenterDao::get_user_by_id($user_id);

    return @data;
}

sub update_user_by_map {
    my ($user_id, $users_fields_map) = @_;
    my $result = Persistance::SystemCenterDao::update_user_by_id($user_id, $users_fields_map);

    return $result;
}

sub update_user_password {
    my ($id, $current_pwd, $new_pwd) = @_;

    $current_pwd = sha256_hex($current_pwd);
    $new_pwd = sha256_hex($new_pwd);

    return Persistance::SystemCenterDao::update_user_password($id, $current_pwd, $new_pwd);
}

sub delete_user {
    my ($id) = @_;

    return Persistance::SystemCenterDao::delete_user_by_id($id);
}

sub reset_user_password {
    my ($id) = @_;
    
    return Persistance::SystemCenterDao::reset_user_password_to_default
           (
                        $id, 
                        sha256_hex(Utils::Constants::NEW_MEMBER_DEFAULT_PASSWORD)
           );
}

sub update_user_option {
    my ($user, $key, $value) = @_;
    my $result = Persistance::SystemCenterDao::update_option_by_user_id($user, $key, $value);

    return $result;
}

sub get_options_for_user {
    my $user_id = shift;
    my @data = Persistance::SystemCenterDao::get_options_by_user_id($user_id);

    return @data;
}

sub check_user_existance {
    my ($name, $password) = @_;

    $password = sha256_hex($password);
    my @users = Persistance::SystemCenterDao::get_user_by_name_and_password($name, $password);
    my $count = @users;
    my $access_token;
    my $user;
    my %check_result = ();

    if ($count) {
        $user = shift @users;
        my $user_id = $user->id;
        my $user_role = Utils::Constants::USER_ROLE_MAP->{$user->role};
        my $cache_client = $get_cache_client->();

        $access_token = Utils::WebUtils::create_uuid();
        
        # Delete old login token to prevent multiple clients using the same username to login
        my $old_token = $cache_client->hget("login_user:$user_id", "token");
        if ($old_token) {
            $cache_client->del("token:$old_token");
        }
        # Start transaction
        $cache_client->multi;

        $cache_client->hmset("token:$access_token", 'user_id' => "$user_id", 'user_role' => "$user_role");
        $cache_client->hmset("login_user:$user_id", 'token' => "$access_token");
        $cache_client->expire("token:$access_token", Utils::Constants::SESSION_TIMEOUT_VALUE);
        $cache_client->expire("login_user:$user_id", Utils::Constants::SESSION_TIMEOUT_VALUE);
        
        # Commit the transaction
        $cache_client->exec;
    }

    $check_result{is_authenticated} = $count;
    $check_result{access_token} = $access_token;
    $check_result{user} = $user;

    return %check_result;
}

sub is_accessible_by_this_role {
    my ($route_name, $role_name) = @_;
    my $cache_client = $get_cache_client->();
    my $is_admin_only = $cache_client->sismember("privileges:admin", $route_name);
    my $is_permitted = 1;

    if ($is_admin_only and $role_name ne 'admin') {
        $is_permitted = 0;
    }

    return $is_permitted;
}

sub load_privileges_map {
    my @privileges = Persistance::SystemCenterDao::get_all_privileges();
    my $cache_client = $get_cache_client->();
    
    $cache_client->multi;
    for my $privilege (@privileges) {
        my $role_name = Utils::Constants::USER_ROLE_MAP->{$privilege->role};
        my $feature = $privilege->feature;

        $cache_client->sadd("privileges:$role_name", $feature);
    }
    $cache_client->exec;
}

sub get_login_user_info {
    my $access_token = shift;
    my $cache_client = $get_cache_client->();
    my %login_user_info =  $cache_client->hgetall("token:$access_token");
    my $user_id = $login_user_info{user_id};

    # Update the TTL of the login session cache
    if (defined $user_id) {
        $cache_client->expire("token:$access_token", Utils::Constants::SESSION_TIMEOUT_VALUE);
        $cache_client->expire("login_user:$user_id", Utils::Constants::SESSION_TIMEOUT_VALUE);
    }

    return %login_user_info;
}

sub add_new_user {
    my ($name, $role) = @_;

    my $password = sha256_hex(Utils::Constants::NEW_MEMBER_DEFAULT_PASSWORD);
    my $result_code = Persistance::SystemCenterDao::add_new_user($name, $password, $role);

    return $result_code;
}

1;
